﻿namespace Blaze.Framework.Loaders
{
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using Logging;
    using UnityEngine;
    using UnityEngine.Networking;

    public class UnityWebRequestLoader : AssetLoaderBase
    {
        public byte[] Bytes
        {
            get { return UnityWebRequest?.downloadHandler.data; }
        }

        /// <summary>
        /// 获取或设置最大重试次数，0表示不重试，负数表示无限重试。
        /// </summary>
        public int MaxRetry { get; set; } = 3;

        public UnityWebRequest UnityWebRequest { get; private set; }

        protected float RetryTime => mRetryCount;

        public override void OnPut()
        {
        }

        protected virtual UnityWebRequest GetRequest()
        {
            var url = GetUrl();
            var ret = UnityWebRequest.Get(url);
            return ret;
        }

        protected string GetUrl()
        {
            if (Uri.StartsWith("http"))
                return Uri;

            //优先考虑PersistentPath
            var persistentPath = PathUtility.GetPersistentDataPath(Uri);
            if (File.Exists(persistentPath))
            {
                var buffer = new StringBuilder();
                if (Application.platform == RuntimePlatform.WindowsEditor
                    || Application.platform == RuntimePlatform.WindowsPlayer)
                    buffer.Append("file:///");
                else
                    buffer.Append("file://");
                buffer.Append(persistentPath);
                return buffer.ToString();
            }

            //其次考虑StreamingAssets
            var streamingAssetsPath = PathUtility.GetStreamingAssetsPath(Uri);
            return streamingAssetsPath;
        }

        protected override void OnDispose()
        {
            base.OnDispose();
            if (mLoaderCoroutine != null)
                CoroutineManager.Stop(mLoaderCoroutine);
            mRetryCount = 0;
            UnityWebRequest = null;
        }

        protected override void OnStart()
        {
            mPendingLoaders.Enqueue(this);
            if (mWorkerCoroutine == null)
                mWorkerCoroutine = CoroutineManager.StartNew(work());
        }

        protected virtual IEnumerator Run()
        {
            UnityWebRequest = GetRequest();
            UnityWebRequest.SendWebRequest();
            while (!UnityWebRequest.isDone)
                yield return null;
            if (!UnityWebRequest.isHttpError && !UnityWebRequest.isNetworkError)
            {
                Finish(null, UnityWebRequest);
            }
            else if (mRetryCount < MaxRetry)
            {
                mRetryCount++;
                mLog.Warn($"[UnityWebRequestTextureLoader]下载错误，{RetryTime}秒后重试 uri={Uri} error={UnityWebRequest.error}");
                UnityWebRequest.Dispose();
                UnityWebRequest = null;
                yield return YielderFactory.WaitForSeconds(RetryTime);
                mPendingLoaders.Enqueue(this);
            }
            else
            {
                var error = UnityWebRequest.error;
                var isSightlyError = UnityWebRequest.isNetworkError || (UnityWebRequest.isHttpError && UnityWebRequest.responseCode == 404);
                mLog.Warn($"[UnityWebRequestTextureLoader]下载失败 retry={mRetryCount} uri={Uri} error={error}");
                UnityWebRequest.Dispose();
                UnityWebRequest = null;
                Finish(error, null, isSightlyError);
            }
        }

        private static IEnumerator work()
        {
            while (true)
            {
                yield return null;

                if (mPendingLoaders.Count == 0)
                    continue;

                var loader = mPendingLoaders.Dequeue();
                loader.mLoaderCoroutine = CoroutineManager.StartNew(loader.Run());
            }
        }

        private static readonly Queue<UnityWebRequestLoader> mPendingLoaders = new Queue<UnityWebRequestLoader>();
        private static Coroutine mWorkerCoroutine;
        private Coroutine mLoaderCoroutine;
        private int mRetryCount;
        private readonly Log mLog = LogManager.GetLogger(typeof(UnityWebRequestLoader));
    }
}